#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dwarf.h>
#include <libdwarf.h>
#include <elf.h>

// 增强的DWARF调试信息解析器
// 使用libdwarf库提供更完整和准确的调试信息处理

typedef struct {
    Dwarf_Debug dbg;
    const char* filename;
} dwarf_context_t;

// 初始化DWARF上下文
int dwarf_init_enhanced(const char* filename, dwarf_context_t* ctx) {
    int res = dwarf_init_path(filename, NULL, 0, 
                             DW_GROUPNUMBER_ANY, NULL, NULL, 
                             &ctx->dbg, NULL);
    if (res != DW_DLV_OK) {
        printf("无法初始化DWARF上下文: %s\n", filename);
        return -1;
    }
    ctx->filename = filename;
    return 0;
}

// 清理DWARF上下文
void dwarf_cleanup_enhanced(dwarf_context_t* ctx) {
    if (ctx->dbg) {
        dwarf_finish(ctx->dbg);
    }
}

// 获取所有编译单元
int dwarf_get_all_compilation_units(dwarf_context_t* ctx) {
    Dwarf_Unsigned cu_header_length;
    Dwarf_Half version_stamp;
    Dwarf_Off abbrev_offset;
    Dwarf_Half address_size;
    Dwarf_Half length_size;
    Dwarf_Half extension_size;
    Dwarf_Sig8 type_signature;
    Dwarf_Unsigned typeoffset;
    Dwarf_Unsigned next_cu_header;
    Dwarf_Half header_cu_type;
    int cu_number = 0;
    
    while (dwarf_next_cu_header_d(ctx->dbg, 1, &cu_header_length,
                                 &version_stamp, &abbrev_offset,
                                 &address_size, &length_size,
                                 &extension_size, &type_signature,
                                 &typeoffset, &next_cu_header,
                                 &header_cu_type, NULL) == DW_DLV_OK) {
        cu_number++;
        printf("编译单元 #%d:\n", cu_number);
        printf("  版本: %d\n", version_stamp);
        printf("  地址大小: %d bytes\n", address_size);
        printf("  长度大小: %d bytes\n", length_size);
    }
    return cu_number;
}

// 获取详细的类型信息
void dwarf_get_type_info(dwarf_context_t* ctx, Dwarf_Die die) {
    Dwarf_Error error;
    Dwarf_Attribute attr;
    Dwarf_Half tag;
    char* name = NULL;
    
    if (dwarf_tag(die, &tag, &error) == DW_DLV_OK) {
        const char* tag_name = NULL;
        if (dwarf_get_TAG_name(tag, &tag_name) == DW_DLV_OK) {
            printf("  DIE标签: %s\n", tag_name);
        }
    }
    
    if (dwarf_diename(die, &name, &error) == DW_DLV_OK) {
        printf("  名称: %s\n", name);
        dwarf_dealloc(ctx->dbg, name, DW_DLA_STRING);
    }
    
    // 获取类型属性
    if (dwarf_attr(die, DW_AT_type, &attr, &error) == DW_DLV_OK) {
        Dwarf_Off type_offset;
        if (dwarf_global_formref(attr, &type_offset, &error) == DW_DLV_OK) {
            printf("  类型引用偏移: 0x%llx\n", (long long)type_offset);
            
            // 尝试获取类型DIE
            Dwarf_Die type_die = NULL;
            if (dwarf_offdie_b(ctx->dbg, type_offset, 1, &type_die, &error) == DW_DLV_OK) {
                char* type_name = NULL;
                if (dwarf_diename(type_die, &type_name, &error) == DW_DLV_OK) {
                    printf("  类型名称: %s\n", type_name);
                    dwarf_dealloc(ctx->dbg, type_name, DW_DLA_STRING);
                }
                
                // 获取类型大小
                Dwarf_Attribute size_attr;
                if (dwarf_attr(type_die, DW_AT_byte_size, &size_attr, &error) == DW_DLV_OK) {
                    Dwarf_Unsigned size;
                    if (dwarf_formudata(size_attr, &size, &error) == DW_DLV_OK) {
                        printf("  类型大小: %llu bytes\n", (unsigned long long)size);
                    }
                    dwarf_dealloc(ctx->dbg, size_attr, DW_DLA_ATTR);
                }
                
                // 检查是否是数组类型，如果是则获取数组信息
                Dwarf_Half type_tag;
                if (dwarf_tag(type_die, &type_tag, &error) == DW_DLV_OK) {
                    if (type_tag == DW_TAG_array_type) {
                        printf("  数组类型信息:\n");
                        
                        // 获取数组元素类型
                        Dwarf_Attribute element_type_attr;
                        if (dwarf_attr(type_die, DW_AT_type, &element_type_attr, &error) == DW_DLV_OK) {
                            Dwarf_Off element_type_offset;
                            if (dwarf_global_formref(element_type_attr, &element_type_offset, &error) == DW_DLV_OK) {
                                Dwarf_Die element_type_die = NULL;
                                if (dwarf_offdie_b(ctx->dbg, element_type_offset, 1, &element_type_die, &error) == DW_DLV_OK) {
                                    char* element_type_name = NULL;
                                    if (dwarf_diename(element_type_die, &element_type_name, &error) == DW_DLV_OK) {
                                        printf("    元素类型: %s\n", element_type_name);
                                        dwarf_dealloc(ctx->dbg, element_type_name, DW_DLA_STRING);
                                    }
                                    
                                    // 获取元素大小
                                    Dwarf_Attribute element_size_attr;
                                    if (dwarf_attr(element_type_die, DW_AT_byte_size, &element_size_attr, &error) == DW_DLV_OK) {
                                        Dwarf_Unsigned element_size;
                                        if (dwarf_formudata(element_size_attr, &element_size, &error) == DW_DLV_OK) {
                                            printf("    元素大小: %llu bytes\n", (unsigned long long)element_size);
                                        }
                                        dwarf_dealloc(ctx->dbg, element_size_attr, DW_DLA_ATTR);
                                    }
                                    
                                    dwarf_dealloc(ctx->dbg, element_type_die, DW_DLA_DIE);
                                }
                            }
                            dwarf_dealloc(ctx->dbg, element_type_attr, DW_DLA_ATTR);
                        }
                        
                        // 获取数组维度信息
                        Dwarf_Die child_die = NULL;
                        if (dwarf_child(type_die, &child_die, &error) == DW_DLV_OK) {
                            int dimension_count = 0;
                            do {
                                Dwarf_Half child_tag;
                                if (dwarf_tag(child_die, &child_tag, &error) == DW_DLV_OK) {
                                    if (child_tag == DW_TAG_subrange_type) {
                                        dimension_count++;
                                        printf("    维度 %d:\n", dimension_count);
                                        
                                        // 获取数组大小
                                        Dwarf_Attribute count_attr;
                                        if (dwarf_attr(child_die, DW_AT_count, &count_attr, &error) == DW_DLV_OK) {
                                            Dwarf_Unsigned count;
                                            if (dwarf_formudata(count_attr, &count, &error) == DW_DLV_OK) {
                                                printf("      元素数量: %llu\n", (unsigned long long)count);
                                            }
                                            dwarf_dealloc(ctx->dbg, count_attr, DW_DLA_ATTR);
                                        }
                                        
                                        // 获取上界
                                        Dwarf_Attribute upper_bound_attr;
                                        if (dwarf_attr(child_die, DW_AT_upper_bound, &upper_bound_attr, &error) == DW_DLV_OK) {
                                            Dwarf_Unsigned upper_bound;
                                            if (dwarf_formudata(upper_bound_attr, &upper_bound, &error) == DW_DLV_OK) {
                                                printf("      上界: %llu\n", (unsigned long long)upper_bound);
                                            }
                                            dwarf_dealloc(ctx->dbg, upper_bound_attr, DW_DLA_ATTR);
                                        }
                                    }
                                }
                                
                                Dwarf_Die next_child = NULL;
                                if (dwarf_siblingof_b(ctx->dbg, child_die, 1, &next_child, &error) == DW_DLV_OK) {
                                    dwarf_dealloc(ctx->dbg, child_die, DW_DLA_DIE);
                                    child_die = next_child;
                                } else {
                                    dwarf_dealloc(ctx->dbg, child_die, DW_DLA_DIE);
                                    break;
                                }
                            } while (child_die != NULL);
                            
                            if (dimension_count > 0) {
                                printf("    总维度数: %d\n", dimension_count);
                            }
                        }
                    }
                }
                
                dwarf_dealloc(ctx->dbg, type_die, DW_DLA_DIE);
            }
        }
        dwarf_dealloc(ctx->dbg, attr, DW_DLA_ATTR);
    }
    
    // 获取变量地址信息（简化版本）
    if (dwarf_attr(die, DW_AT_location, &attr, &error) == DW_DLV_OK) {
        Dwarf_Block* block;
        if (dwarf_formblock(attr, &block, &error) == DW_DLV_OK) {
            if (block->bl_len > 0) {
                printf("  位置信息: 块大小 %llu bytes\n", (unsigned long long)block->bl_len);
            }
            dwarf_dealloc(ctx->dbg, block, DW_DLA_BLOCK);
        }
        dwarf_dealloc(ctx->dbg, attr, DW_DLA_ATTR);
    }
}

// 递归遍历DIE树查找变量
static int traverse_die_for_variable(dwarf_context_t* ctx, Dwarf_Die die, const char* var_name) {
    Dwarf_Error error;
    int found = 0;
    
    if (!die) return 0;
    
    // 首先递归遍历子DIE
    Dwarf_Die child_die = NULL;
    if (dwarf_child(die, &child_die, &error) == DW_DLV_OK) {
        int child_found = traverse_die_for_variable(ctx, child_die, var_name);
        found = found || child_found;
        dwarf_dealloc(ctx->dbg, child_die, DW_DLA_DIE);
    }
    
    // 然后检查当前DIE
    Dwarf_Half tag;
    char* name = NULL;
    
    if (dwarf_tag(die, &tag, &error) == DW_DLV_OK) {
        // 检查是否是变量或函数（扩展搜索范围以包含数组等类型）
        if (tag == DW_TAG_variable || tag == DW_TAG_formal_parameter || 
            tag == DW_TAG_subprogram || tag == DW_TAG_member ||
            tag == DW_TAG_array_type || tag == DW_TAG_typedef ||
            tag == DW_TAG_structure_type || tag == DW_TAG_union_type) {
            
            if (dwarf_diename(die, &name, &error) == DW_DLV_OK) {
                if (name && strcmp(name, var_name) == 0) {
                    printf("找到符号: %s (标签: ", var_name);
                    
                    // 获取标签名称
                    const char* tag_name = NULL;
                    if (dwarf_get_TAG_name(tag, &tag_name) == DW_DLV_OK) {
                        printf("%s)\n", tag_name);
                    } else {
                        printf("未知)\n");
                    }
                    
                    dwarf_get_type_info(ctx, die);
                    found = 1;
                }
                dwarf_dealloc(ctx->dbg, name, DW_DLA_STRING);
            }
        }
    }
    
    // 最后遍历兄弟DIE
    Dwarf_Die sibling_die = NULL;
    Dwarf_Bool is_info = 1;
    if (dwarf_siblingof_b(ctx->dbg, die, is_info, &sibling_die, &error) == DW_DLV_OK) {
        int sibling_found = traverse_die_for_variable(ctx, sibling_die, var_name);
        found = found || sibling_found;
        dwarf_dealloc(ctx->dbg, sibling_die, DW_DLA_DIE);
    }
    
    return found;
}

// 增强的变量信息查询
int dwarf_get_variable_info_enhanced(dwarf_context_t* ctx, const char* var_name) {
    Dwarf_Error error;
    Dwarf_Die cu_die = NULL;
    int found = 0;
    
    // 遍历所有编译单元
    Dwarf_Unsigned cu_header_length;
    Dwarf_Half version_stamp;
    Dwarf_Off abbrev_offset;
    Dwarf_Half address_size;
    Dwarf_Half length_size;
    Dwarf_Half extension_size;
    Dwarf_Sig8 type_signature;
    Dwarf_Unsigned typeoffset;
    Dwarf_Unsigned next_cu_header;
    Dwarf_Half header_cu_type;
    
    // 重置到第一个编译单元
    dwarf_next_cu_header_d(ctx->dbg, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
    
    while (dwarf_next_cu_header_d(ctx->dbg, 1, &cu_header_length,
                                 &version_stamp, &abbrev_offset,
                                 &address_size, &length_size,
                                 &extension_size, &type_signature,
                                 &typeoffset, &next_cu_header,
                                 &header_cu_type, NULL) == DW_DLV_OK) {
        
        // 获取编译单元的DIE
        Dwarf_Bool is_info = 1;
        if (dwarf_siblingof_b(ctx->dbg, NULL, is_info, &cu_die, &error) == DW_DLV_OK) {
            found = traverse_die_for_variable(ctx, cu_die, var_name);
            dwarf_dealloc(ctx->dbg, cu_die, DW_DLA_DIE);
        }
        
        // 继续遍历所有编译单元，不提前break
        // 这样可以确保找到所有匹配的变量
    }
    
    if (!found) {
        printf("未找到符号: %s\n", var_name);
    }
    
    return found;
}

// 主测试函数
int main(int argc, char** argv) {
    if (argc != 2) {
        printf("用法: %s <可执行文件>\n", argv[0]);
        return 1;
    }
    
    dwarf_context_t ctx;
    if (dwarf_init_enhanced(argv[1], &ctx) == 0) {
        printf("=== 增强的DWARF信息分析 ===\n");
        printf("文件: %s\n\n", argv[1]);
        
        int cu_count = dwarf_get_all_compilation_units(&ctx);
        printf("总共找到 %d 个编译单元\n\n", cu_count);
        
        // 测试变量查找 - 针对test_variable_types.c中的变量
        printf("=== 变量信息查询 ===\n");
        dwarf_get_variable_info_enhanced(&ctx, "global_int_var");
        dwarf_get_variable_info_enhanced(&ctx, "global_float_var");
        dwarf_get_variable_info_enhanced(&ctx, "global_double_var");
        dwarf_get_variable_info_enhanced(&ctx, "global_char_var");
        dwarf_get_variable_info_enhanced(&ctx, "global_string_var");
        dwarf_get_variable_info_enhanced(&ctx, "global_array_var");
        dwarf_get_variable_info_enhanced(&ctx, "global_struct_var");
        dwarf_get_variable_info_enhanced(&ctx, "global_union_var");
        dwarf_get_variable_info_enhanced(&ctx, "main");
        dwarf_get_variable_info_enhanced(&ctx, "print_variables");
        
        dwarf_cleanup_enhanced(&ctx);
    }
    
    return 0;
}